import logging
import math
from datetime import timedelta
from typing import Dict, Any, List, Optional, Tuple
from sqlalchemy.orm import Session

from app.services.coordinate_service import CoordinateService
from app.services.gps_service import GPSApiService
from app.crud.shipment import shipment
from app.crud.sys_config import sys_config
from app.utils.timezone_util import now_china, timestamp_ms_to_china, localize_datetime

logger = logging.getLogger(__name__)


class ShipmentMonitorService:
    """
    货物监控任务服务
    """
    
    def __init__(self, db: Session):
        self.db = db
    
    def calculate_distance(self, lat1: float, lng1: float, lat2: float, lng2: float) -> float:
        """
        计算两个坐标点之间的距离（米）
        使用Haversine公式
        """
        # 转换为弧度
        lat1, lng1, lat2, lng2 = map(math.radians, [lat1, lng1, lat2, lng2])
        
        # Haversine公式
        dlat = lat2 - lat1
        dlng = lng2 - lng1
        a = math.sin(dlat/2)**2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlng/2)**2
        c = 2 * math.asin(math.sqrt(a))
        
        # 地球半径（米）
        r = 6371000
        
        return c * r
    
    def is_within_range(self, target_coords: str, check_coords: Dict[str, float], error_range: float) -> bool:
        """
        检查坐标是否在误差范围内
        
        Args:
            target_coords: 目标坐标字符串 "经度,纬度"
            check_coords: 检查的坐标 {"lng": 经度, "lat": 纬度}
            error_range: 误差范围（米）
            
        Returns:
            是否在范围内
        """
        try:
            coordinate_service = CoordinateService("", "")
            parsed_coords = coordinate_service.parse_coordinates(target_coords)
            
            if not parsed_coords:
                return False
            
            distance = self.calculate_distance(
                parsed_coords['lat'], parsed_coords['lng'],
                check_coords['lat'], check_coords['lng']
            )
            
            return distance <= error_range
            
        except Exception as e:
            logger.error(f"坐标范围检查失败: {str(e)}")
            return False
    
    def get_config_value(self, code: str, default_value: Any = None) -> Any:
        """
        获取系统配置值
        """
        try:
            config_value = sys_config.get_value_by_code(self.db, code=code)
            if config_value is not None:
                # 尝试转换为相应的数据类型
                if isinstance(default_value, int):
                    return int(config_value)
                elif isinstance(default_value, float):
                    return float(config_value)
                else:
                    return config_value
            return default_value
        except Exception as e:
            logger.warning(f"获取配置失败 {code}: {str(e)}")
            return default_value
    
    def find_coordinate_match_in_track(
        self, 
        track_points: List[Dict], 
        target_coords: str, 
        error_range: float
    ) -> Optional[Dict]:
        """
        在轨迹点中查找与目标坐标匹配的点
        
        Args:
            track_points: 轨迹点列表
            target_coords: 目标坐标
            error_range: 误差范围
            
        Returns:
            匹配的轨迹点，没有匹配返回None
        """
        for point in track_points:
            if not point.get('lat') or not point.get('lng'):
                continue
                
            if self.is_within_range(target_coords, point, error_range):
                return point
                
        return None
    
    def process_shipment_tracking(self, shipment_obj, gps_service: GPSApiService) -> Dict[str, Any]:
        """
        处理单个货物的追踪逻辑
        
        Args:
            shipment_obj: 货物对象
            gps_service: GPS服务实例
            
        Returns:
            处理结果
        """
        try:
            # 获取配置
            from_minus_min = self.get_config_value('shipmentFromMinusMin', 60)
            error_range = self.get_config_value('coordinateErrorRange', 300.0)
            
            # 计算查询时间范围
            current_time = now_china()
            start_timestamp = None
            # 如果有开始时间，使用开始时间作为起点，否则使用当前时间减去配置的分钟数
            if shipment_obj.start_time:
                # 确保时间有正确的时区信息
                start_time = localize_datetime(shipment_obj.start_time)
            else:
                start_timestamp = int(start_time.timestamp() * 1000)
            
            end_time = current_time
            start_timestamp = int(start_time.timestamp() * 1000)
            end_timestamp = int(end_time.timestamp() * 1000)

            logger.info(f"处理货物 {shipment_obj.number_no} 的追踪，时间范围: {start_time} - {end_time},时间戳（毫秒）: {start_timestamp} - {end_timestamp}")

            # 获取历史轨迹
            track_result = gps_service.get_device_history_track(
                shipment_obj.mac_id, 
                start_timestamp, 
                end_timestamp
            )
            
            if not track_result['success']:
                return {
                    'success': False,
                    'message': f"获取轨迹失败: {track_result['message']}"
                }
            
            track_points = track_result['data']
            if not track_points:
                return {
                    'success': True,
                    'message': '暂无轨迹数据',
                    'action': 'no_data'
                }
            
            logger.info(f"获取到 {len(track_points)} 个轨迹点")
            
            # 检查状态和坐标匹配
            result = self._check_coordinate_matches(shipment_obj, track_points, error_range)
            
            return result
            
        except Exception as e:
            logger.error(f"处理货物追踪失败 {shipment_obj.number_no}: {str(e)}")
            return {
                'success': False,
                'message': f"处理失败: {str(e)}"
            }
    
    def _check_coordinate_matches(self, shipment_obj, track_points: List[Dict], error_range: float) -> Dict[str, Any]:
        """
        检查坐标匹配逻辑
        """
        pickup_coords = shipment_obj.pickup_warehouse_coordinates
        delivery_coords = shipment_obj.delivery_warehouse_coordinates
        current_status = shipment_obj.status
        
        # 查找取货坐标匹配
        pickup_match = None
        if pickup_coords:
            pickup_match = self.find_coordinate_match_in_track(track_points, pickup_coords, error_range)
        
        # 查找卸货坐标匹配
        delivery_match = None
        if delivery_coords:
            delivery_match = self.find_coordinate_match_in_track(track_points, delivery_coords, error_range)
        
        # 根据当前状态和匹配情况决定处理逻辑
        if current_status == 0:  # 未开始状态
            if pickup_match and delivery_match:
                # 同时匹配到取货和卸货点，直接完成
                return self._complete_shipment(shipment_obj, pickup_match, delivery_match)
            elif pickup_match:
                # 只匹配到取货点，开始追踪
                return self._start_shipment(shipment_obj, pickup_match)
            else:
                return {'success': True, 'message': '未到达取货点', 'action': 'waiting'}
                
        elif current_status == 10:  # 进行中状态
            if delivery_match:
                # 匹配到卸货点，完成追踪
                return self._complete_shipment_from_progress(shipment_obj, delivery_match)
            else:
                return {'success': True, 'message': '运输中，未到达卸货点', 'action': 'in_progress'}
        
        return {'success': True, 'message': f'状态 {current_status} 无需处理', 'action': 'skip'}
    
    def _start_shipment(self, shipment_obj, pickup_match: Dict) -> Dict[str, Any]:
        """
        开始货物追踪
        """
        try:
            # 转换时间戳为datetime
            start_time = timestamp_ms_to_china(pickup_match['timestamp'])
            
            shipment.update_status_and_time(
                self.db,
                id=shipment_obj.id,
                status=10,  # 进行中
                start_time=start_time,
                execution_info=f"已到达取货点，开始追踪。取货时间: {start_time}",
                updated_by="system"
            )
            
            logger.info(f"货物 {shipment_obj.number_no} 开始追踪，取货时间: {start_time}")
            
            return {
                'success': True,
                'message': '开始追踪',
                'action': 'started',
                'start_time': start_time
            }
            
        except Exception as e:
            logger.error(f"开始追踪失败: {str(e)}")
            return {
                'success': False,
                'message': f"开始追踪失败: {str(e)}"
            }
    
    def _complete_shipment(self, shipment_obj, pickup_match: Dict, delivery_match: Dict) -> Dict[str, Any]:
        """
        完成货物追踪（从未开始直接到完成）
        """
        try:
            start_time = timestamp_ms_to_china(pickup_match['timestamp'])
            end_time = timestamp_ms_to_china(delivery_match['timestamp'])
            
            shipment.update_status_and_time(
                self.db,
                id=shipment_obj.id,
                status=30,  # 完成
                start_time=start_time,
                end_time=end_time,
                execution_info=f"运输完成。取货时间: {start_time}，卸货时间: {end_time}",
                updated_by="system"
            )
            
            logger.info(f"货物 {shipment_obj.number_no} 运输完成，取货: {start_time}，卸货: {end_time}")
            
            return {
                'success': True,
                'message': '运输完成',
                'action': 'completed',
                'start_time': start_time,
                'end_time': end_time,
                'should_remove': True  # 标记需要从定时任务中移除
            }
            
        except Exception as e:
            logger.error(f"完成追踪失败: {str(e)}")
            return {
                'success': False,
                'message': f"完成追踪失败: {str(e)}"
            }
    
    def _complete_shipment_from_progress(self, shipment_obj, delivery_match: Dict) -> Dict[str, Any]:
        """
        完成货物追踪（从进行中到完成）
        """
        try:
            end_time = timestamp_ms_to_china(delivery_match['timestamp'])
            
            shipment.update_status_and_time(
                self.db,
                id=shipment_obj.id,
                status=30,  # 完成
                end_time=end_time,
                execution_info=f"{shipment_obj.execution_info or ''}\n运输完成，卸货时间: {end_time}",
                updated_by="system"
            )
            
            logger.info(f"货物 {shipment_obj.number_no} 运输完成，卸货时间: {end_time}")
            
            return {
                'success': True,
                'message': '运输完成',
                'action': 'completed',
                'end_time': end_time,
                'should_remove': True  # 标记需要从定时任务中移除
            }
            
        except Exception as e:
            logger.error(f"完成追踪失败: {str(e)}")
            return {
                'success': False,
                'message': f"完成追踪失败: {str(e)}"
            }